﻿$(function () {

    var uigrid = {

        $cells: $(),
        _renderCache: [],

        hintsDrawer: null,

        init: function () {
            //this.$element = new GridCreator().createGrid();
            //$("#screen").append(this.$element);
            this.$element = $("#grid");
            this.discoverChildren();
            this.bindEvents();
            this.storeSelf();
            this.hintsDrawer = new GridHintsDrawer(this);
        },

        discoverChildren: function () {
            this.$cells = this.$element.find(".cell");
            this.candidatesCache = this.createCandidatesCache(this.$cells);
        },

        bindEvents: function () {
            EVENTBROKER.gridTopic.on(TOPIC_EVENTS.gridFill, this.onGridFill.bind(this));
            EVENTBROKER.gridTopic.on(TOPIC_EVENTS.gridFlashGlowCells, this.onGridFlashGlowCells.bind(this));

            this.$cells.on("tap", this.onCellClick.bind(this));
            this.$cells.on("tapdown", this.setActive.bind(this));
            this.$cells.on("tapup", this.removeActive.bind(this));
        },

        storeSelf: function () {
            this.$element.data("grid", this);
        },

        createCandidatesCache: function (cells) {
            var cache = [];
            for (var i = 0; i < 81; i++) {
                cache[i] = $(cells[i]).find(".candidate");

            }
            return cache;
        },

        onCellClick: function (ev, data) {
            var cell = ev.currentTarget;
            var n = this.$cells.index(cell);
            EVENTBROKER.gridTopic.trigger(TOPIC_EVENTS.gridOnCellSelected, IndicesHelper.getIndicesFromRank(n));
        },

        setActive: function (ev) {
            var $cell = $(ev.currentTarget);
            $cell.addClass("active");
        },

        removeActive: function (ev) {
            var $cell = $(ev.currentTarget);
            $cell.removeClass("active");
        },

        onGridFill: function (ev, sudokuGrid) {
            for (var i = 0; i < 9; i++) {
                for (var j = 0; j < 9; j++) {
                    this.updateCell(sudokuGrid.gridModel.cells[i][j]);
                }
            }
            this.onGridUpdateHightlight(ev, sudokuGrid);
        },

        onGridUpdateHightlight: function (ev, sudokuGrid) {
            this._renderSelection(sudokuGrid);
            this._renderSimilars(sudokuGrid);
            this._renderErrors(sudokuGrid);
            this._renderCheckErrors(sudokuGrid);
        },

        onGridFlashGlowCells: function (ev, cellsIndices) {
            for (var i = 0; i < cellsIndices.length; i++) {
                var cell = this.findCell(cellsIndices[i]);
                cell.classList.add("glow");
            }

            setTimeout(function () {
                for (var i = 0; i < cellsIndices.length; i++) {
                    var cell = this.findCell(cellsIndices[i]);
                    cell.classList.remove("glow");
                }
            }.bind(this), 100);

        },

        updateCell: function (cellModel) {
            var n = IndicesHelper.getRankFromIndices(cellModel.indices);
            var cell = this.$cells[n];

            var newModelHash = cellModel.getHash();
            if (cell.modelHash !== newModelHash) {
                cell.modelHash = newModelHash;
                var $cell = $(cell);
                $cell.toggleClass("isbase", cellModel.isBase);

                if (cellModel.value === 0) {
                    $cell.addClass("show-candidates");
                    this._updateCandidates($cell, cellModel);
                }
                else {
                    $cell.removeClass("show-candidates");
                    $cell.find(".single .value").html(cellModel.value);
                }
            }
        },

        _updateCandidates: function ($cell, cellModel) {
            $cell.find(".candidate").removeClass("visible");

            for (var i = 1; i < 10; i++) {
                if (cellModel.candidates.has[i]) {
                    var candidate = $cell.find(".candidate" + i);
                    candidate.addClass("visible");
                }
            }
        },

        findCandidate: function (cellIndices, candidateValue) {
            return this.candidatesCache[IndicesHelper.getRankFromIndices(cellIndices)][candidateValue - 1];
        },

        findCandidates: function (cellIndices, candidatesValues) {
            var candidates = [];
            for (var i = 0; i < candidatesValues.length; i++) {
                candidates.push(this.findCandidate(cellIndices, candidatesValues[i]));
            }
            return candidates;
        },

        findCandidatesInCells: function (cellsIndices, candidatesValue) {
            var candidates = [];
            for (var i = 0; i < cellsIndices.length; i++) {
                var cellIndices = cellsIndices[i];
                candidates.pushArray(this.findCandidates(cellIndices, candidatesValue));
            }
            return candidates;
        },

        findCandidateInCells: function (cellsIndices, candidateValue) {
            var candidates = [];
            for (var i = 0; i < cellsIndices.length; i++) {
                var cellIndices = cellsIndices[i];
                candidates.push(this.findCandidate(cellIndices, candidateValue));
            }
            return candidates;
        },


        findCell: function (indices) {
            return this.$cells[IndicesHelper.getRankFromIndices(indices)];
        },

        findCells: function (cellsIndices) {
            var cells = [];
            for (var i = 0; i < cellsIndices.length; i++) {
                cells.push(this.findCell(cellsIndices[i]));
            }
            return cells;
        },

        _renderSelection: function (sudokuGrid) {
            this.renderClassOnCellsIndices(sudokuGrid.selectedCellIndices ? [sudokuGrid.selectedCellIndices] : [], 'selected');
        },

        _renderSimilars: function (sudokuGrid) {
            this.renderClassOnCellsIndices(sudokuGrid.similarCellsIndices, 'similar-highlight');
        },

        _renderErrors: function (sudokuGrid) {
            this.renderClassOnCellsIndices(sudokuGrid.errorCellsIndices, 'error');
        },

        _renderCheckErrors: function (sudokuGrid) {
            this.renderClassOnCellsIndices(sudokuGrid.checkErrorCellsIndices, 'checkError');
        },

        renderClassOnCellsIndices: function (cellsIndices, className) {
            this._unrenderClass(className);
            this._renderClassOnCells(this.findCells(cellsIndices), className);
        },

        _unrenderClass: function (className) {
            var $renderedCells = this._renderCache[className];
            if ($renderedCells)
                $renderedCells.removeClass(className);
        },

        _renderClassOnCells: function (cells, className) {
            var $cells = $(cells);
            $cells.addClass(className);
            this._renderCache[className] = $cells;
        }
    }

    uigrid.init();

});
